import os
import yaml
import logging
from typing import Dict, Any, Optional

class ConfigManager:
    """配置管理器，支持从YAML文件加载配置"""
    
    def __init__(self, config_path: Optional[str] = None):
        self.config: Dict[str, Any] = {}
        self.config_path = config_path
        self.logger = logging.getLogger(__name__)
        
        # 默认配置
        self.default_config = {
            "engine": {
                "initial_capital": 1000000,    # 初始资金
                "commission": 0.0003,          # 交易手续费率
                "margin_ratio": 0.12,          # 保证金比例
                "contract_multiplier": 300,    # 合约乘数
                "allow_short": True            # 允许做空
            },
            "data": {
                "cache_dir": "./data_cache",   # 数据缓存路径
                "cache_ttl": 86400,            # 缓存有效期（秒）
                "benchmarks": ["sh000300"]     # 业绩比较基准
            },
            "risk": {
                "max_position": 0.1,           # 最大持仓比例
                "max_loss": 0.05,              # 最大亏损比例
                "max_drawdown": 0.2,           # 最大回撤限制
                "volatility_limit": 0.03,      # 波动率限制
                "correlation_threshold": 0.7,  # 相关性阈值
                "max_concentration": 0.3,      # 最大行业集中度
                "max_leverage": 1.5            # 最大杠杆率
            },
            "strategy": {
                "type": "dual_ma",             # 策略类型
                "params": {                    # 策略参数
                    "fast_window": 5,
                    "slow_window": 20
                }
            },
            "logging": {
                "level": "INFO",               # 日志级别
                "file": "./logs/backtest.log", # 日志文件
                "console": True                # 是否输出到控制台
            }
        }
        
        # 如果提供了配置文件路径，则加载配置
        if config_path:
            self.load_config(config_path)
        else:
            self.config = self.default_config.copy()
            self.logger.info("使用默认配置")
    
    def load_config(self, config_path: str) -> Dict[str, Any]:
        """从YAML文件加载配置"""
        try:
            if not os.path.exists(config_path):
                self.logger.warning(f"配置文件不存在: {config_path}，使用默认配置")
                self.config = self.default_config.copy()
                return self.config
                
            with open(config_path, 'r', encoding='utf-8') as f:
                loaded_config = yaml.safe_load(f)
                
            # 合并配置，使用加载的配置覆盖默认配置
            merged_config = self.default_config.copy()
            self._deep_update(merged_config, loaded_config)
            self.config = merged_config
            
            self.logger.info(f"成功加载配置: {config_path}")
            return self.config
            
        except Exception as e:
            self.logger.error(f"配置加载失败: {str(e)}", exc_info=True)
            self.config = self.default_config.copy()
            return self.config
    
    def _deep_update(self, d: Dict[str, Any], u: Dict[str, Any]) -> Dict[str, Any]:
        """深度更新字典"""
        for k, v in u.items():
            if isinstance(v, dict) and k in d and isinstance(d[k], dict):
                self._deep_update(d[k], v)
            else:
                d[k] = v
        return d
    
    def get(self, section: str, key: str, default: Any = None) -> Any:
        """获取配置项"""
        try:
            return self.config.get(section, {}).get(key, default)
        except Exception:
            return default
    
    def get_section(self, section: str) -> Dict[str, Any]:
        """获取配置节"""
        return self.config.get(section, {})
    
    def save_config(self, config_path: Optional[str] = None) -> bool:
        """保存配置到YAML文件"""
        path = config_path or self.config_path
        if not path:
            self.logger.error("未指定配置文件路径")
            return False
            
        try:
            # 确保目录存在
            os.makedirs(os.path.dirname(os.path.abspath(path)), exist_ok=True)
            
            with open(path, 'w', encoding='utf-8') as f:
                yaml.dump(self.config, f, default_flow_style=False, allow_unicode=True)
                
            self.logger.info(f"配置已保存: {path}")
            return True
        except Exception as e:
            self.logger.error(f"配置保存失败: {str(e)}", exc_info=True)
            return False
    
    def update_config(self, section: str, key: str, value: Any) -> None:
        """更新配置项"""
        if section not in self.config:
            self.config[section] = {}
        self.config[section][key] = value
        self.logger.debug(f"更新配置: {section}.{key} = {value}")